<?php


namespace App\Repositories;


use App\Models\Warehousing as Model;
use App\Traits\CodeTrait;
use App\Traits\Logs;
use Exception;
use LTools\Repositories\RepositoryAbstract;
use PhpOffice\PhpSpreadsheet\Cell\DataType;
use PhpOffice\PhpSpreadsheet\Reader\Xlsx;
use PhpOffice\PhpSpreadsheet\Spreadsheet;

class Warehousing extends RepositoryAbstract
{

    use CodeTrait, Logs;

    /**
     * Warehousing constructor.
     * @param Model $model
     */
    public function __construct(Model $model)
    {
        $this->model = $model;
    }

    public function paginate(array $attributes, int $perPage = null, array $columns = ['*'], $pageName = 'page', int $page = null)
    {
        return $this->model->with(['customer'])->where(
            $attributes
        )->paginate($perPage, $columns, $pageName, $page);
    }

    /**
     * @param array $attributes
     * @return bool|\Illuminate\Database\Eloquent\Model
     */
    public function create(array $attributes = [])
    {
        $productCollect = collect($attributes['products']);
        $attributes['code'] = $this->unique(4, 'WR' . date('ymd'));
        $attributes['price'] = $productCollect->sum(function ($item) {
            return $item['price'] * $item['quantity'];
        });
        $attributes['product_count'] = $productCollect->count();
        /** @var Model $model */
        $model = parent::create($attributes);
        foreach ($attributes['products'] as $product) {
            $product['product_id'] = \App\Models\Product::query()
                ->where('status', '=', 3)
                ->where('code', '=', $product['code'])
                ->where('customer_id', '=', $attributes['customer_id'])
                ->value('id');

            $model->products()->create(
                collect($product)->only(['product_id', 'barcode', 'quantity', 'price'])->toArray()
            );
        }

        $this->recordLogs($model, '创建入库单成功');

        return $model;

    }

    /**
     * @param $id
     * @param array $columns
     * @return \Illuminate\Database\Eloquent\Builder|\Illuminate\Database\Eloquent\Builder[]|\Illuminate\Database\Eloquent\Collection|\Illuminate\Database\Eloquent\Model
     */
    public function edit($id, $columns = ['*'])
    {
        return $this->model->with(['products.product'])->findOrFail($id, $columns);
    }

    /**
     * @param $id
     * @param array $columns
     * @return \Illuminate\Database\Eloquent\Builder|\Illuminate\Database\Eloquent\Builder[]|\Illuminate\Database\Eloquent\Collection|\Illuminate\Database\Eloquent\Model
     */
    public function show($id, $columns = ['*'])
    {
        return $this->model->with(['customer', 'products.product', 'logs.user', 'files', 'tally.product'])->findOrFail($id, $columns);
    }

    /**
     * @param $id
     * @param array $values
     * @return bool|\Illuminate\Database\Eloquent\Model|void
     * @throws \Throwable
     */
    public function update($id, array $values)
    {
        /** @var Model $model */
        $model = $this->model->newQuery()->where('id', '=', $id)->lockForUpdate()->first();
        if ($model->getAttribute('status') !== 0 && $model->getAttribute('status') !== 2) {
            throw new Exception('入库单状态不正确不能修改入库单');
        }

        $productCollect = collect($values['products']);
        $values['price'] = $productCollect->sum(function ($item) {
            return $item['price'] * $item['quantity'];
        });
        $values['product_count'] = $productCollect->count();
        $values['status'] = 0;

        /** @var Model $model */
        $model->fillable(array_merge($model->getFillable(), ['status']))->fill($values)->saveOrFail();
        $model->products()->delete();

        $productCollect->each(function ($product) use ($model, $values) {
            $product['product_id'] = \App\Models\Product::query()
                ->where('status', '=', 3)
                ->where('code', '=', $product['code'])
                ->where('customer_id', '=', $values['customer_id'])
                ->value('id');

            $model->products()->create(
                collect($product)->only(['product_id', 'barcode', 'quantity', 'price'])->toArray()
            );
        });
        $this->recordLogs($model, '修改入库单成功');

        return $model;
    }

    /**
     * @param $id
     * @return bool|mixed
     * @throws \Exception
     */
    public function delete($id)
    {
        /** @var Model $model */
        $model = $this->model->newQuery()->where('id', '=', $id)->lockForUpdate()->first();
        if ($model->getAttribute('status') === 0) {
            $model->products()->delete();
            $model->logs()->delete();
            $model->delete();
            return true;
        }
        throw new Exception('入库单状态不正确不能删除入库单');
    }

    /**
     * @param $id
     * @param $remark
     * @return Model
     * @throws \Throwable
     * @author luffyzhao@vip.126.com
     */
    public function reject($id, $remark)
    {
        /** @var Model $model */
        $model = $this->model->newQuery()->where('id', '=', $id)->lockForUpdate()->first();
        if ($model->getAttribute('status') === 1) {
            $model->setAttribute('status', 2);
            $model->saveOrFail();
                $this->recordLogs($model, '驳回入库单成功:' . $remark);
            return $model;
        }
        throw new Exception('入库单状态不正确不能驳回入库单');
    }

    /**
     * @param $id
     * @return Model
     * @throws \Throwable
     * @author luffyzhao@vip.126.com
     */
    public function review($id)
    {
        /** @var Model $model */
        $model = $this->model->newQuery()->where('id', '=', $id)->lockForUpdate()->first();
        if ($model->getAttribute('status') === 1) {
            $model->setAttribute('status', 3);
            $model->saveOrFail();
            $this->recordLogs($model, '入库单审核通过');
            return $model;
        }
        throw new Exception('入库单状态不正确不能审核入库单');
    }

    /**
     * @param $id
     * @return Model
     * @throws \Throwable
     * @author luffyzhao@vip.126.com
     */
    public function confirm($id)
    {
        /** @var Model $model */
        $model = $this->model->newQuery()->where('id', '=', $id)->lockForUpdate()->first();
        if ($model->getAttribute('status') === 0) {
            $model->setAttribute('status', 1);
            $model->saveOrFail();

            $this->recordLogs($model, '确认入库单成功');

            return $model;
        }
        throw new Exception('入库单状态不正确不能确认入库单');
    }

    /**
     * @param $id
     * @param array $attributes
     * @return Model
     */
    public function files($id, array $attributes)
    {
        /** @var Model $model */
        $model = $this->find($id);
        $model->files()->create($attributes);
        $this->recordLogs($model, "文件[{$attributes['remark']}]上传成功");
        return $model;
    }

    /**
     * @param $id
     * @return Model
     * @throws \Throwable
     * @author luffyzhao@vip.126.com
     */
    public function arrival($id)
    {
        /** @var Model $model */
        $model = $this->model->newQuery()->where('id', '=', $id)->lockForUpdate()->first();
        if ($model->getAttribute('status') === 3) {
            $model->setAttribute('status', 4);
            $model->saveOrFail();
            $model->products->each(function ($item) {
                /** @var Tally $tally */
                $tally = app(Tally::class);
                $tally->create([
                    'product_id' => $item['product_id'],
                    'barcode' => $item['barcode'],
                    'warehousing_id' => $item['warehousing_id'],
                    'quantity' => $item['quantity'],
                ]);
            });
            $this->recordLogs($model, '确认入库单成功');

            return $model;
        }
        throw new Exception('入库单状态不正确不能确认入库单');
    }

    /**
     * @param $id
     * @return Model
     * @throws \Throwable
     * @author luffyzhao@vip.126.com
     */
    public function compete($id)
    {
        /** @var Model $model */
        $model = $this->model->newQuery()->where('id', '=', $id)->lockForUpdate()->first();
        if ($model->getAttribute('status') === 4) {
            $model->setAttribute('status', 5);
            $model->saveOrFail();

            $tallyCount = $model->tally()->whereIn('status', [0, 1])->count();
            if($tallyCount > 0){
                throw new Exception('入库单还有未理货的产品，不能完成！');
            }

            $shelvesCount = $model->shelves()->where('status', '=', 0)->count();
            if($shelvesCount > 0){
                throw new Exception('入库单还有未上架的产品，不能完成！');
            }
            return $model;
        }
        throw new Exception('入库单状态不正确不能完成入库单');
    }


    /**
     * @param $id
     * @return false|string
     * @throws \PhpOffice\PhpSpreadsheet\Writer\Exception
     * @throws \PhpOffice\PhpSpreadsheet\Exception
     */
    public function windowTemplate($id)
    {
        $reader = new Xlsx();
        $spreadsheet = $reader->load(storage_path('template/单一窗口核注清单导入模板.xlsx'));

        $worksheet = $spreadsheet->getSheet(1);

        /** @var Model $model */
        $model = $this->find($id);
        $model->loadMissing(['products.product.customs']);


        $model->products->each(function ($item, $key) use ($worksheet) {
            // 序号
            $worksheet->getCellByColumnAndRow(1, $key + 2)->setValue($key + 1);
            // 备案序号 账册还没开发。
             $worksheet->getCellByColumnAndRow(2, $key + 2)->setValue($item['product']['customs']['book']['record_no']);
            // 商品料号
            $worksheet->getCellByColumnAndRow(3, $key + 2)
                ->setValue($item['product']['customs']['unique']);
            // 报关单序号
            $worksheet->getCellByColumnAndRow(4, $key + 2)->setValue($key + 1);
            // 流转申报表序号
            // $worksheet->getCellByColumnAndRow(5, $key + 2)->setValue($key + 1);
            // 商品编码
            $worksheet->getCellByColumnAndRow(6, $key + 2)->setValue($item['product']['customs']['code']);
            // 商品名称
            $worksheet->getCellByColumnAndRow(7, $key + 2)->setValue($item['product']['customs']['name']);
            // 商品规格
            $worksheet->getCellByColumnAndRow(8, $key + 2)->setValue($item['product']['customs']['element']);
            // 币制
            $worksheet->getCellByColumnAndRow(9, $key + 2)->setValue(142);
            // 申报计量单位代码
            $worksheet->getCellByColumnAndRow(10, $key + 2)->setValue($item['product']['customs']['unit']);
            // 法定计量单位代码
            $worksheet->getCellByColumnAndRow(11, $key + 2)->setValue($item['product']['customs']['unit1']);
            // 法定第二计量单位代码
            $worksheet->getCellByColumnAndRow(12, $key + 2)->setValue($item['product']['customs']['unit2']);
            // 申报数量
            $worksheet->getCellByColumnAndRow(13, $key + 2)->setValue($item['quantity']);
            // 法定数量
            $worksheet->getCellByColumnAndRow(14, $key + 2)->setValue($item['quantity'] * $item['product']['customs']['qy1']);
            // 第二法定数量
            $worksheet->getCellByColumnAndRow(15, $key + 2)->setValue($item['quantity'] * $item['product']['customs']['qy2']);
            // 申报单价
            $worksheet->getCellByColumnAndRow(16, $key + 2)->setValue($item['price']);
            // 申报总价
            $worksheet->getCellByColumnAndRow(17, $key + 2)->setValue($item['quantity'] * $item['price']);
            // 原产国(地区）
            $worksheet->getCellByColumnAndRow(18, $key + 2)->setValue($item['product']['customs']['country']);
            // 最终目的国（地区）
            $worksheet->getCellByColumnAndRow(19, $key + 2)->setValue(142);
            // 净重
            $worksheet->getCellByColumnAndRow(24, $key + 2)->setValue($item['product']['customs']['net_weight'] * $item['quantity']);
            // 征免方式
            $worksheet->getCellByColumnAndRow(25, $key + 2)->setValue(3);
        });

        $writer = new \PhpOffice\PhpSpreadsheet\Writer\Xlsx($spreadsheet);
        $writer->save("php://output");
    }

    /**
     * @param $id
     * @throws \PhpOffice\PhpSpreadsheet\Writer\Exception
     * @throws \PhpOffice\PhpSpreadsheet\Exception
     */
    public function windowTally($id){
        $reader = new Xlsx();
        $spreadsheet = $reader->load(storage_path('template/入库单理货模板.xlsx'));
        $worksheet = $spreadsheet->getSheet(0);

        /** @var Model $model */
        $model = $this->find($id);
        $model->loadMissing(['tally.product']);

        $worksheet->getCellByColumnAndRow(1, 1)->setValue("入库单[{$model['code']}]理货模板");

        $model->tally->each(function ($item, $key) use ($worksheet) {
            // 序号
            $worksheet->getCellByColumnAndRow(1, $key + 3)->setValue($key + 1);
            $worksheet->getCellByColumnAndRow(2, $key + 3)->setValue($item['product']['code'])->setDataType(DataType::TYPE_STRING);
            $worksheet->getCellByColumnAndRow(3, $key + 3)->setValue($item['product']['title']);
            $worksheet->getCellByColumnAndRow(4, $key + 3)->setValue($item['barcode'])->setDataType(DataType::TYPE_STRING);
            $worksheet->getCellByColumnAndRow(5, $key + 3)->setValue($item['code']);
            $worksheet->getCellByColumnAndRow(6, $key + 3)->setValue($item['quantity']);
            $worksheet->getCellByColumnAndRow(7, $key + 3)->setValue($item['send'] ? $item['send'] : '');
        });

        $writer = new \PhpOffice\PhpSpreadsheet\Writer\Xlsx($spreadsheet);
        $writer->save("php://output");
    }

    /**
     * @param $id
     * @throws \PhpOffice\PhpSpreadsheet\Exception
     * @throws \PhpOffice\PhpSpreadsheet\Writer\Exception
     */
    public function windowBatch($id){
        $reader = new Xlsx();
        $spreadsheet = $reader->load(storage_path('template/入库单收货模板.xlsx'));
        $worksheet = $spreadsheet->getSheet(0);

        /** @var Model $model */
        $model = $this->find($id);
        $model->loadMissing(['shelves.product']);

        $worksheet->getCellByColumnAndRow(1, 1)->setValue("入库单[{$model['code']}]收货模板");

        $model->shelves->each(function ($item, $key) use ($worksheet) {
            // 序号
            $worksheet->getCellByColumnAndRow(1, $key + 3)->setValue($key + 1);
            $worksheet->getCellByColumnAndRow(2, $key + 3)->setValue($item['product']['code'])->setDataType(DataType::TYPE_STRING);
            $worksheet->getCellByColumnAndRow(3, $key + 3)->setValue($item['product']['title']);
            $worksheet->getCellByColumnAndRow(4, $key + 3)->setValue($item['barcode'])->setDataType(DataType::TYPE_STRING);
            $worksheet->getCellByColumnAndRow(5, $key + 3)->setValue($item['attribute'] ? '不良品' : '良品');
            $worksheet->getCellByColumnAndRow(6, $key + 3)->setValue($item['batch']);
            $worksheet->getCellByColumnAndRow(7, $key + 3)->setValue($item['quantity']);
        });

        $writer = new \PhpOffice\PhpSpreadsheet\Writer\Xlsx($spreadsheet);
        $writer->save("php://output");
    }

}
